// STL
#include <fstream>             // std::ofstream
#include <limits>              // std::numeric_limits<>
#include <string>              // std::string
#include <vector>              // std::vector<>

// jScience
#include "jScience/linalg.hpp" // Matrix<>

// stats++
#include "statsxx/machine_learning/NeuralNet.hpp" // NEURAL_NET


//
// DESC: Tests an MLP.
//
void test_MLP(
              NEURAL_NET                     &mlp,
              // -----
              const std::vector<std::string> &label,
              const Matrix<double>           &X_in,
              const Matrix<double>           &X_out,
              // -----
              const double                    cutoff,
              // -----
              const std::string               prefix
              )
{
    std::ofstream ofs(("./" + prefix + ".test.out.dat"));
    ofs.precision(std::numeric_limits<double>::max_digits10);

    std::ofstream ofs_c;

    if( mlp.m_isClassif )
    {
        ofs_c.open(("./" + prefix + ".classifications.dat"));
    }

    for(auto i = 0; i < X_in.size(0); ++i)
    {
        std::vector<std::vector<double>> input(
                                               1,
                                               X_in.row(i).std_vector()
                                               );
        std::vector<double> output;
        mlp.evaluate(
                     input,
                     output
                     );

        // OUTPUT
        for(auto j = 0; j < X_out.size(1); ++j)
        {
            ofs << output[j];

            if( j != (X_out.size(1)-1) )
            {
                ofs << '\t';
            }
        }

        ofs << '\n';

        // CLASSIFICATION
        if( mlp.m_isClassif )
        {
            // NOTE: A probabilistic classified produces a discrete (binary) output, using a threshold.
            // NOTE: ... If the classifier output is *above* the threshold, it produces a 1, else a 0.
            //
            // NOTE: ... See T. Fawcett.
            if( output[0] > cutoff )
            {
                ofs_c << "1" << '\n';
            }
            else
            {
                ofs_c << "0" << '\n';
            }

        }
    }

    ofs.close();

    if( mlp.m_isClassif )
    {
        ofs_c.close();
    }
}
